---@diagnostic disable: different-requires
local ffi = require 'ffi'
local message = require("jass.message")
local runtime = require("jass.runtime")

ffi.cdef [[
    int ADD(int a, int b);
    int system(const char *command);
    int GetFocus();
    bool IsZoomed(int hwnd);
    int IsIconic(int hwnd);
    int SetWindowPos(int hwnd,int hWndInsertAfter,int x,int y,int cx,int cy,int wFlags);
    int FindWindowA(const char * lpClassName,const char * lpWindowName);
    bool DestroyWindow(void*);
    int GetConsoleWindow();
    int GetActiveWindow();
    int rand();
    void srand(int seed);
    int GetSystemMetrics(int index);
    const char * GetCommandLineA();
    int GetModuleHandleA(const char* lpModuleName);
    bool SetWindowTextW(int hwnd, const wchar_t* lpString);
    int MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char* lpMultiByteStr, int cbMultiByte, wchar_t* lpWideCharStr, int cchWideChar);
    int WideCharToMultiByte(unsigned int CodePage, unsigned long dwFlags, const wchar_t* lpWideCharStr, int cchWideChar, char* lpMultiByteStr, int cchMultiByte, const char* lpDefaultChar, int* pfUsedDefaultChar);
    // 设置无边框窗口等设置
    int GetWindowLongA(int hWnd, int nIndex);
    int SetWindowLongA(int hWnd, int nIndex, int dwNewLong);
    typedef struct {
        int x;
        int y;
    } POINT;
    typedef struct {
        int32_t left;
        int32_t top;
        int32_t right;
        int32_t bottom;
    } RECT;
    typedef struct {
        uint32_t cbSize;
        RECT rcMonitor;
        RECT rcWork;
        uint32_t dwFlags;
    } MONITORINFO;
    typedef struct {
        uint32_t length;
        uint32_t flags;
        uint32_t showCmd;
        POINT ptMinPosition;
        POINT ptMaxPosition;
        struct {
            int32_t left;
            int32_t top;
            int32_t right;
            int32_t bottom;
        } rcNormalPosition;
    } WINDOWPLACEMENT;
    int MonitorFromWindow(void* hwnd, uint32_t dwFlags);
    int SetWindowPlacement(void* hWnd, WINDOWPLACEMENT* lpwndpl);
    int GetMonitorInfoA(int hMonitor, MONITORINFO* lpmi);
    int GetWindowPlacement(void* hWnd, WINDOWPLACEMENT* lpwndpl);
    // 修改窗口标题
    int SetWindowTextA(int hwnd, const char* lpString);
    // 修改程序img
    typedef void* HANDLE;
    typedef HANDLE HICON;
    typedef long LONG_PTR;
    typedef long DWORD;
    HICON LoadImageA(HANDLE hinst, const char* lpszName, unsigned int uType, int cxDesired, int cyDesired, unsigned int fuLoad);
    int SendMessageA(int hwnd, unsigned int Msg, unsigned int wParam, LONG_PTR lParam);
    DWORD GetLastError();

    // 加载文件
    uint32_t LoadLibraryA(const char* lpFileName);
    typedef void (*ffi_anyfunc)();
    ffi_anyfunc GetProcAddress(uint32_t hModule, uint32_t ord);

    typedef bool (*__stdcall SFileOpenArchive)(const char* szArchivename, unsigned long dwPriority, unsigned long dwFlags, uint32_t* handle);
    typedef bool (*__stdcall SFileLoadFile)(const char* filename, const void** pbuf, uint32_t* plen, uint32_t reservelen, void* overlapped_ptr);
    typedef bool (*__stdcall SFileUnloadFile)(const void* buf);
    // 移除进程
    bool TerminateProcess(int a,int b);
    int GetCurrentProcess();
]]
local mt = {}

local _, cmd_line = xpcall(ffi.C["GetCommandLineA"], runtime["error_handle"])
if cmd_line then
    _, cmd_line = xpcall(ffi["string"], runtime["error_handle"], cmd_line)
end

cmd_line = cmd_line or ""
cmd_line = cmd_line:lower()
function mt.cmd_line()
    return cmd_line
end

local opengl_flag = cmd_line:find("-opengl")
-- 游戏渲染模式
function mt.is_opengl_mode()
    return opengl_flag
end

-- IsWindowMode
local window_flag = cmd_line:find("-window")
function mt.is_window_flag()
    return opengl_flag
end

-- 是窗口模式
function mt.is_window_mode()
    return window_flag
end

local black_flag = false
local replay_flag = false
local observe_flag = false
local list = message.load_window_infos()
for _, info in ipairs(list) do
    local title = info.title or ""
    title = title:lower()
    if title:find("background") then
        black_flag = true
        log.print("黑边模式")
    elseif title:find("直播") then
        observe_flag = true
        log.print("观战模式")
    elseif title:find("录像") then
        replay_flag = true
        log.print("录像模式")
    end
end
-- 观战模式
function mt.is_observe()
    return observe_flag
end

-- 录像模式
function mt.is_replay()
    return replay_flag
end

-- 判断是黑边模式
function mt.is_black_mode()
    return black_flag
end

-- 执行命令
function mt.system_cmd(cmd)
    local _, value = xpcall(crt["system"], runtime["error_handle"], cmd)
    return value
end

-- 窗口宽度
function mt.system_window_width()
    local _, value = xpcall(ffi.C["GetSystemMetrics"], runtime["error_handle"], 0)
    return value or 1920
end

-- 窗口高度
function mt.system_window_height()
    local _, value = xpcall(ffi.C["GetSystemMetrics"], runtime["error_handle"], 1)
    return value or 1080
end

-- 窗口是最大化
function mt.is_zoomed()
    local bool, ret = xpcall(ffi.C["IsZoomed"], runtime["error_handle"], war3_hwnd)
    if not bool then
        ret = true
    end
    return ret
end

-- 窗口是最小化
function mt.is_iconic()
    local bool, ret = xpcall(ffi.C["IsIconic"], runtime["error_handle"], war3_hwnd)
    if not bool then
        return false
    end
    return 0 < ret
end

-- 设置窗口位置
function mt.set_window_pos(x, y, width, height, flag)
    xpcall(ffi.C["SetWindowPos"], runtime["error_handle"], war3_hwnd, 0, x, y, width, height, flag)
end

-- 设置窗口大小
function mt.set_window_size(width, height, is_center)
    if war3_hwnd == 0 then
        return
    end
    if window_flag and not mt.is_zoomed() then
        width = math.floor(width)
        height = math.floor(height)
        if is_center then
            local x = math.floor((mt.system_window_width() - width) / 2)
            local y = math.floor((mt.system_window_height() - height) / 2)
            mt.set_window_pos(x, y, width, height, 4)
        else
            mt.set_window_pos(0, 0, width, height, 6)
        end
    end
end

-- 设置控制台位置
function mt.set_console_pos(x, y)
    ffi.C["SetWindowPos"](ffi.C["GetConsoleWindow"](), 0, x, y, 0, 0, 1)
end

-- 保存窗口位置信息的全局变量
local g_wpPrev = ffi.new("WINDOWPLACEMENT")
-- 设置窗口为无边框模式
function mt.SetBorderless(width, height)
    width = width or mt.system_window_width()
    height = height or mt.system_window_height()
    local hwnd = war3_hwnd
    -- 获取窗口当前样式
    local dwStyle = ffi.C['GetWindowLongA'](hwnd, -16) -- GWL_STYLE
    -- 保存窗口位置信息
    g_wpPrev.length = ffi.sizeof(g_wpPrev)
    ffi.C['GetWindowPlacement'](hwnd, g_wpPrev)
    -- 移除窗口边框和标题栏样式
    dwStyle = dwStyle | 0x800000    -- WS_POPUP
    dwStyle = dwStyle & ~0x00C00000 -- WS_CAPTION
    dwStyle = dwStyle & ~0x00040000 -- WS_THICKFRAME
    -- 设置新的窗口样式
    ffi.C["SetWindowLongA"](hwnd, -16, dwStyle)
    -- 刷新窗口
    local x = math.floor((mt.system_window_width() - width) / 2)
    local y = math.floor((mt.system_window_height() - height) / 2)
    ffi.C["SetWindowPos"](hwnd, nil, x, y, width, height, 0x0020 | 0x0004 | 0x0010) -- SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE
end

-- 设置全屏为窗口化
function mt.SetWindowed(width, height)
    local hWnd = war3_hwnd
    local SWP_SHOWWINDOW = 0x0040
    local SWP_FRAMECHANGED = 0x0020
    local SW_HIDE = 0
    local SW_SHOWNORMAL = 1
    local SW_SHOWMINIMIZED = 2
    local SW_SHOWMAXIMIZED = 3
    local SW_MAXIMIZE = 3
    local SW_SHOWNOACTIVATE = 4
    local SW_SHOW = 5
    local SW_MINIMIZE = 6
    local SW_SHOWMINNOACTIVE = 7
    local SW_SHOWNA = 8
    local SW_RESTORE = 9
    local WS_OVERLAPPEDWINDOW = 0x00CF0000
    local GWL_STYLE = -16
    local MONITOR_DEFAULTTONEAREST = 0x00000002
    local HWND_TOPMOST = -1
    local HWND_NOTOPMOST = -2
    local SWP_NOACTIVATE = 0x0010
    local SWP_NOOWNERZORDER = 0x0200
    local POINT = ffi.new("POINT")
    local WINDOWPLACEMENT = ffi.new("WINDOWPLACEMENT")
    WINDOWPLACEMENT.length = ffi.sizeof("WINDOWPLACEMENT")
    if ffi.C["GetWindowPlacement"](hWnd, WINDOWPLACEMENT) == 0 then
        return false
    end
    local hMonitor = ffi.C["MonitorFromWindow"](hWnd, MONITOR_DEFAULTTONEAREST)
    local monitorInfo = ffi.new("MONITORINFO")
    monitorInfo.cbSize = ffi.sizeof("MONITORINFO")
    if ffi.C["GetMonitorInfoA"](hMonitor, monitorInfo) == 0 then
        return false
    end
    width = width or mt.system_window_width()
    height = height or mt.system_window_height()
    local left = (monitorInfo.rcMonitor.right - width) / 2
    local top = (monitorInfo.rcMonitor.bottom - height) / 2
    WINDOWPLACEMENT.showCmd = SW_SHOWNORMAL
    WINDOWPLACEMENT.rcNormalPosition.left = left
    WINDOWPLACEMENT.rcNormalPosition.top = top
    WINDOWPLACEMENT.rcNormalPosition.right = left + width
    WINDOWPLACEMENT.rcNormalPosition.bottom = top + height
    if ffi.C["SetWindowPlacement"](hWnd, WINDOWPLACEMENT) == 0 then
        return false
    end
    -- 获取当前窗口样式
    local style = ffi.C["GetWindowLongA"](hWnd, GWL_STYLE)
    -- 设置新的窗口样式，确保包含 WS_OVERLAPPEDWINDOW
    ffi.C["SetWindowLongA"](hWnd, GWL_STYLE, style | WS_OVERLAPPEDWINDOW)
    ffi.C["SetWindowPos"](hWnd, HWND_TOPMOST, left, top, width, height, SWP_SHOWWINDOW | SWP_FRAMECHANGED)
    return true
end

-- 设置窗口大小16:9 并居中,fullScreen
function mt.init_window_size()
    -- print("设置窗口大小16:9 并居中")
    if mt.is_replay() or mt.is_observe() or mt.is_zoomed() then
        return
    end
    if mt.is_black_mode() then
        mt.set_window_size(mt.system_window_width(), mt.system_window_height(), true)
    elseif mt.is_window_mode() then
        local width = math.min(mt.system_window_width() * 0.8, 1920)
        local height = width * 1080 / 1920
        if height >= mt.system_window_height() * 0.9 then
            height = math.min(mt.system_window_height() * 0.8, 1080)
            width = height * 1920 / 1080
        end
        mt.set_window_size(width, height, true)
    end
end

-- 判断是窗口模式
if mt.is_window_mode() then
    mt.init_window_size() -- 设置16:9且居中
    -- else
    --     mt.SetWindowed()      -- 强制窗口化游戏
end

-- utf8编码转换
local function utf8_to_wide_string(utf8_str)
    local CP_UTF8 = 65001
    local size_needed = ffi.C["MultiByteToWideChar"](CP_UTF8, 0, utf8_str, #utf8_str, nil, 0)
    local wide_str = ffi.new("wchar_t[?]", size_needed + 1)
    ffi.C["MultiByteToWideChar"](CP_UTF8, 0, utf8_str, #utf8_str, wide_str, size_needed)
    return wide_str
end
-- 设置窗口标题
function mt.set_window_title(title)
    local wide_title = utf8_to_wide_string(title)
    print(title,war3_hwnd, wide_title)
    xpcall(ffi.C["SetWindowTextW"], runtime["error_handle"], war3_hwnd, wide_title)
end

-- 设置窗口图标
function mt.set_window_icon(icon_path)
    local WM_SETICON = 0x0080
    local ICON_SMALL = 0
    local ICON_BIG = 1
    local IMAGE_ICON = 1
    local LR_LOADFROMFILE = 0x0010
    local hIcon = ffi.C['LoadImageA'](nil, icon_path, IMAGE_ICON, 0, 0, LR_LOADFROMFILE)
    if hIcon == nil then
        local error_code = ffi.C["GetLastError"]()
        log.print("加载图标失败:" .. tostring(error_code))
        return
    end
    local result_small = ffi.C["SendMessageA"](war3_hwnd, WM_SETICON, ICON_SMALL, ffi.cast("LONG_PTR", hIcon))
    if result_small == 0 then
        local error_code = ffi.C["GetLastError"]()
        log.print("加载图标失败:" .. tostring(error_code))
        log.print("设置小图标失败: " .. icon_path .. ", error: " .. tostring(error_code))
    else
        log.print("小图标设置成功: " .. icon_path)
    end
    local result_big = ffi.C["SendMessageA"](war3_hwnd, WM_SETICON, ICON_BIG, ffi.cast("LONG_PTR", hIcon))
    if result_big == 0 then
        local error_code = ffi.C["GetLastError"]()
        log.print("设置大图标失败: " .. icon_path .. ", error: " .. tostring(error_code))
    else
        log.print("大图标设置成功: " .. icon_path)
    end
    log.print("图标设置完成: " .. icon_path)
end


-- local map_img_path = ("%s\\resources\\map_img.ico"):format("lightning")
-- storm.save(map_img_path, storm.load("map_img.tga"))
-- mt.set_window_icon(map_img_path)
mt.set_window_title('新窗口')



return mt
